﻿#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>

#include "mylib_parse.h"
#include "os.h"

#define MAX_CHAPTER_NAME_LEN 256
struct chapter_item{
	char title[MAX_CHAPTER_NAME_LEN];
	char url[MAX_CHAPTER_NAME_LEN];
};

struct chapter_item gurl;
static char read_buf[BUF_SIZE];
char gcmd[MAX_CMD_LEN];

char output_path[] = "temp";
//static char test_link_name[] = "https://www.zhihu.com/column/c_1301456161237876736";

/*
 * output_dir: e.g. temp
 * file_name: e.g. 1.jpg
 * final output: temp/1.jpg or temp\1.jpg
 * path: url address
 * */
void exec_curl(char* output_dir, char* file_name, char* path)
{
	char cmd[512];

#if defined(WINDOWS)
	sprintf(cmd, "%s\\%s", output_dir, file_name);
#else
	sprintf(cmd, "%s/%s", output_dir, file_name);
#endif

	if(FileExists(cmd))
		return;

#if defined(WINDOWS)
	sprintf(cmd, "curl -o %s\\%s %s", output_dir, file_name, path);
#else
	sprintf(cmd, "curl -o %s/%s %s", output_dir, file_name, path);
#endif

	system(cmd);
}

//Horizontal Rules
void write_latex_hor(FILE* fp)
{
	fprintf(fp, "***\n");
}

/*
  # Heading level 1
  chapter name
*/
static void write_head(FILE* fp, char* title, int level)
{
	if(level == 1)
		fprintf(fp, "\n# %s\n\n", title);
	else if(level == 2)
		fprintf(fp, "\n## %s\n\n", title);
	else if (level == 3)
		fprintf(fp, "\n### %s\n\n", title);
}

/*
* ![The San Juan Mountains are beautiful!](/assets/images/san-juan-mountains.jpg "San Juan Mountains")
* ![alt text](path "title")
*/
static void write_image_path(FILE* fp, char* name, char* title)
{
	if (title) {
		fprintf(fp, "\n![%s](%s \"%s\")\n\n", name, name, title);
		fprintf(fp, "    %s\n", title);
	} else {
		fprintf(fp, "\n![%s](%s)\n\n", name, name);
	}
}

/*
* My favorite search engine is [Duck Duck Go](https://duckduckgo.com)
* [text](url)
*/
static void write_link(FILE* fp, char* text, char* url)
{
	if (!text)
		text = url;
	if (!url)
		url = text;
	fprintf(fp, "[%s](%s)", text, url);
}

/*
* ordered list
1. First item
2. Second item
3. Third item
4. Fourth item
*/
//jpg, png, gif
//in: url
//out: filename
void get_filename(char* url, char* filename)
{
	char* temp;
	int len;

	if (filename)
		filename[0] = 0;

	temp = strstr(url, "jpg");
	if (!temp) {
		temp = strstr(url, "gif");
		if (!temp) {
			temp = strstr(url, "png");
		}
	}
	if (!temp) {
		printf("unsupported format %s\n", url);
		return;
	}

	len = 0;
	while (*temp != '/') {
		temp--;
		len++;
	}
	temp++;
	len += 2; //jpg, png, gif
	strncpy(filename, temp, len);
	filename[len] = 0;
}

/* case 2: https://zhuanlan.zhihu.com/p/599417117
<figure data-size="normal">
	 <div>
		 <div class="GifPlayer css-1isopsn" data-size="normal" data-za-detail-view-path-module="GifItem">
		 <img class="ztext-gif" width="1280" role="presentation" 
		 src="./vim配置_files/v2-b2a40b349414b8935a0269ce86f21955_b.jpg" 
		 data-thumbnail="https://pic2.zhimg.com/v2-b2a40b349414b8935a0269ce86f21955_b.jpg" 
		 data-size="normal" alt="动图封面" style="display: block;">
			 <div class="GifPlayer-icon css-d39tw7"><svg width="50" height="50" viewBox="0 0 60 60" xmlns="http://www.w3.org/2000/svg"></g>
			 ....
					</svg>
				</svg></div>
		</div>
	</div>
</figure>
*/

char* get_gif_attr_src(lxb_dom_element_t* node)
{
	//case 1
	//only care <img src="xxx.jpg">
	/* single file
	* data-size=normal data-rawwidth=1904 data-rawheight=993 data-qrcode-action=none
	data-original-token=v2-57c515a0ef817f89b419721ed0a2a2d4
	class="origin_image zh-lightbox-thumb" width=1904
	data-original=https://pic2.zhimg.com/v2-6a6c93c21d63482fdd967acf9c6c0919_r.jpg>
	</div><figcaption>图1：信号与系统知识脉络图</figcaption></figure>
	*/

	size_t value_len;
	char* str;
	str = (char*)lxb_dom_element_get_attribute(node, "data-original", strlen("data-original"), &value_len);
	if (str)
		return str;

	//case 2:
	str = (char*)lxb_dom_element_get_attribute(node, "data-thumbnail", strlen("data-thumbnail"), &value_len);
	return str;
}

/*
download figure and modify path
<figure>
	<noscript>
		<img src="https://xx.jpg?source=1940ef5c" data-rawwidth="1024"/>
	</noscript>
	<img src="data:image/svg+xml;/>
</figure>

modified to:
<figure> <img src="1.jpg"/> </figure>

*/
static void download_image(FILE* fp, lxb_dom_node_t* node)
{
	lxb_dom_collection_t* sub_collection;
	lxb_dom_element_t* element;

	char* path;
	char file_name[256];
	char* text = NULL;

	/*
	  <figure data-size="normal">
		<img src= "..." >
		 <figcaption>图1：靶</figcaption>
    </figure>
	 * */
	//get image text
	sub_collection = get_nodes_by_tag(node, "figcaption");
	if (sub_collection) {
		size_t len = lxb_dom_collection_length(sub_collection);
		if (len) {
			element = lxb_dom_collection_element(sub_collection, 0);
			lxb_dom_node_t* child;
			child = lxb_dom_node_first_child(lxb_dom_interface_node(element));
			if (child) {
				text = lxb_dom_node_text_content(child, NULL);
			}
		}
		lxb_dom_collection_destroy(sub_collection, true);
	}

	//get image url
	sub_collection = get_nodes_by_tag(node, "img");;
	if (!sub_collection)
		return;
	
	element = lxb_dom_collection_element(sub_collection, 0);
	if(!element)
		goto exit;
	path = get_gif_attr_src(element);
	if(!path)
		goto exit;

	if (strncmp(path, "https", strlen("https")))
		goto exit;
	//https://pic2.zhimg.com/50/v2-cf4f9a768fa23924d207f69994b5dbe9_hd.jpg
	get_filename(path, file_name);

	if(text) {
		write_image_path(fp, file_name, text);
	} else {
		write_image_path(fp, file_name, NULL);
	}

	exec_curl(output_path, file_name, path);
exit:
	lxb_dom_collection_destroy(sub_collection, true);
}

/*
<ol>
    <li data-pid="RQAztloK">
        <b>基本</b>
        信号：正弦信号、指数信号、单位脉冲、单位阶跃；
    </li>
    <li data-pid="6Q_cH5MD">
        信号的<b>基本</b>
        运算：数乘、加法、乘法、时移、时间翻转、时间尺度变换；
    </li>
</ol>
* */
void handle_ul(FILE* fp, lxb_dom_node_t* node)
{
	lxb_dom_collection_t* collection;
	collection = get_nodes_by_tag(node, "li");
	if (!collection)
		return;

	lxb_tag_id_t tag = lxb_dom_node_tag_id(node);
	size_t i;
	size_t len = lxb_dom_collection_length(collection);
	lxb_dom_element_t* element;
	lxb_char_t* str;
	size_t str_len;
	fprintf(fp, "\n");
	for (i = 0; i < len; i++) {
		element = lxb_dom_collection_element(collection, i);
		str = lxb_dom_node_text_content(lxb_dom_interface_node(element), &str_len);
		if (str) {
			if (tag == LXB_TAG_UL) {
				fprintf(fp, "- %s\n", str);
			} else {
				fprintf(fp, "%zd. %s\n", i + 1, str);
			}
		}
	}
	fprintf(fp, "\n");

	lxb_dom_collection_destroy(collection, true);
}

/*
<a target="_blank" href="https://link.zhihu.com/?target=https%3A//gitee.com/gentheaven/openssl_dec" 
data-draft-node="block" data-draft-type="link-card" 
data-text="openssl_dec: parse TLS packets" class="LinkCard new">

return "openssl_dec: parse TLS packets"
*/
char* href_data_text(lxb_dom_node_t* node)
{
	lxb_dom_attr_t* attr;
	attr = lxb_dom_element_attr_by_name(lxb_dom_interface_element(node),
		"data-text", strlen("data-text"));
	if (!attr)
		return 0;
	const lxb_char_t* str = lxb_dom_attr_value(attr, NULL);
	return (char*)str;
}

//https://link.zhihu.com/?target=https%3A//gitee.com/gentheaven/openssl_dec
//to https://gitee.com/gentheaven/openssl_dec
const lxb_char_t zhihu_prefix[] = "https://link.zhihu.com/?target=https%3A//";
void get_clean_url(char* url)
{
	const lxb_char_t* found = lexbor_str_data_ncasecmp_first(url,
		zhihu_prefix, strlen(zhihu_prefix));
	if (!found)
		return;
	//remove prefix
	char temp[2048];
	sprintf(temp, "https://%s", found);
	strcpy(url, temp);
}

/*
<li id = "ref_1" tabindex = "0">
    <a href = "#ref_1_0" reference-link = "true"> ^ </a>
    <span>...</span>
</li>
*/
void handle_tagA(FILE* fp, lxb_dom_node_t* node)
{
	char* text = NULL;
	char* extra = NULL;
	char url[2048];

	get_a_href(node, url);
	get_clean_url(url);
	extra = url;

	lxb_dom_node_t* child = lxb_dom_node_first_child(node);
	if (!child)
		return;
	lxb_tag_id_t tag = lxb_dom_node_tag_id(child);
	if (LXB_TAG__TEXT != tag && LXB_TAG_SPAN != tag)
		return;
	text = lxb_dom_node_text_content(child, NULL);
	if (!*text) {
		text = href_data_text(node);
	}

	//<span> stext </span>
	char* stext;
	char all_text[512];
	lxb_dom_node_t* next = lxb_dom_node_next(node);
	if (next) {
		stext = lxb_dom_node_text_content(next, NULL);
		if (stext) {
			lxb_dom_node_t* parent = lxb_dom_node_parent(node);
			if (lxb_dom_node_tag_id(parent) == LXB_TAG_LI) {
				sprintf(all_text, "%s %s", text, stext);
				text = all_text;
			}
		}
	}

	if (text || extra) {
		write_link(fp, text, extra);
		fprintf(fp, "\n");
	}
}

/* case 2
* https://zhuanlan.zhihu.com/p/599417117
* ctrlp https://github.com/kien/ctrlp.vim
* <tr>
	<td>ctrlp</td>
	<td>
	<a href="https://link.zhihu.com/?target=https%3A//github.com/kien/ctrlp.vim"
	class=" external" target="_blank" rel="nofollow noreferrer" data-za-detail-view-id="1043">
	<span class="invisible">https://</span><span class="visible">github.com/kien/ctrlp.v</span>
	<span class="invisible">im</span><span class="ellipsis"></span></a>
	</td>
</tr>
*/
static char url_link[1024];
char* get_td_text(lxb_dom_node_t* node)
{
	char* text = NULL;
	lxb_tag_id_t tag;

	if (!node)
		return NULL;
	text = lxb_dom_node_text_content(node, NULL);
	if (text)
		return text; //case 1: <td>cJson</td>

	//case 2
	lxb_dom_node_t* child = lxb_dom_node_first_child(node);
	if (!child)
		return NULL;
	tag = lxb_dom_node_tag_id(child);
	size_t len;
	if (tag == LXB_TAG_A) {
		//<a href="https://link.zhihu.com/?target=https%3A//github.com/kien/ctrlp.vim"
		text = (char*)lxb_dom_element_get_attribute(lxb_dom_interface_element(child), "href", strlen("href"), &len);
		if (!text)
			return NULL;
		//printf("%s\n", text);
		//https://link.zhihu.com/?target=https%3A//github.com/kien/ctrlp.vim
		char* head = strstr(text, "target=https");
		if (!head)
			return NULL;
		text = head + strlen("target=https%3A");
		sprintf(url_link, "https:%s", text);
		return url_link;
	}
	return NULL;
}


/* case 1
<table border="1">
	<tbody>
		<tr>
			<th>库名称</th>
			<th>用途</th>
			<th>静态库还是动态库</th>
		</tr>
		<tr>
			<td>cJson</td>
			<td>Json 解析器</td>
			<td>源代码</td>
		</tr>
	</tbody>
</table>
*/
void handle_table_items(FILE* fp, lxb_dom_node_t* node, int is_head)
{
	char* text;
	lxb_dom_node_t* next = node;

	int cnt = 0;
	while (next) {
		text = get_td_text(next);
		if (!text) {
			next = lxb_dom_node_next(next);
			continue;
		}
		next = lxb_dom_node_next(next);
		cnt++;
		fprintf(fp, "| %s ", text);
	}

	//line end
	fprintf(fp, " |\n");
	if (!is_head)
		return;

	//left align
	int i;
	for (i = 0; i < cnt; i++) {
		fprintf(fp, "| :------");
	}
	//line end
	fprintf(fp, " |\n");
}

/*
 <table data-draft-node="block" data-draft-type="table" data-size="normal" data-row-style="normal">
	<tbody>
		<tr>
			<th>库名称</th>
			<th>用途</th>
			<th>静态库还是动态库</th>
		</tr>
		<tr>
			<td>Myhtml</td>
			<td>HTML 解析器</td>
			<td>静态库</td>
		</tr>
	</tbody>
</table>
*/
void handle_table(FILE* fp, lxb_dom_node_t* node)
{
	lxb_tag_id_t tag;
	lxb_dom_node_t* child;

	child = lxb_dom_node_first_child(node);
	if (!child)
		return;
	tag = lxb_dom_node_tag_id(child);
	if(tag == LXB_TAG_TBODY)
		child = lxb_dom_node_first_child(child);
	if (!child)
		return;

	//child point to <tr>
	lxb_dom_node_t* next = child;
	fprintf(fp, "\n");
	//traverse <tr>
	while (next) {
		child = lxb_dom_node_first_child(next);
		if (!child)
			continue;
		tag = lxb_dom_node_tag_id(child);
		if (tag == LXB_TAG_TD) {
			//<td>cJson</td>
			handle_table_items(fp, child, 0);
		} else if (tag == LXB_TAG_TH) {
			//<th>xxx</th>
			handle_table_items(fp, child, 1);
		}
		//coninue to handle next node
		next = lxb_dom_node_next(next);
	}
	fprintf(fp, "\n");

}

// <p> text </p>
void write_content_text(FILE* fp, lxb_dom_node_t* node, char* text)
{
	if (!text)
		return;
	//special words
	char* str;
	str = strstr(text, "<iframe>");

	if (str) {
		*str = 0;
		str = str + strlen("<iframe>");
		// <iframe> changed to  `<iframe>`
			fprintf(fp, "%s`<iframe>`%s\n\n", text, str);
	} else {
			fprintf(fp, "%s\n\n", text);
	}
}

/* get file name without path and extension
* windows: ..\xxx\filename.html to filename
*/
char* get_single_file_name(char* filename)
{
	//get file name
	char *ptr, *temp, *head;
	ptr = strstr(filename, ".html");
	if (!ptr)
		return NULL;
	head = filename;
	temp = head;
	char symbol;
#if defined(WINDOWS)
	symbol = '\\';
#else
	symbol = '/';
#endif
	while (temp != ptr) {
		if (*temp == symbol)
		{
			temp++;
			head = temp;
		}
		temp++;
	}
	*temp = 0;
	//end of get file name
	return head;
}

FILE* creat_markdown_file(char* path)
{
	char file_name[1024];
	FILE* fp = NULL;
	strcpy(file_name, path);
	char* name = get_single_file_name(path);
	if (!name)
		return NULL;

	// temp\xxx.md
	sprintf(file_name, "%s%s.md", OUTPUT_PATH, name);
	fp = fopen(file_name, "w");
	return fp;
}

/* 	title, url, cover
	<meta data-rh=true property=og:title content=信号与系统漫谈系列之开篇>
	<meta data-rh=true property=og:url content=https://zhuanlan.zhihu.com/p/461247854>
  <meta data-rh="true" property="og:image"
  content="https://pica.zhimg.com/v2-751c0ed764f67908bc360993fc305648_720w.jpg?
  source=172ae18b"/>
*/
lexbor_action_t meta_walker(lxb_dom_node_t* node, void* ctx)
{
	FILE* fp = (FILE*)ctx;
	if (node->type != LXB_DOM_NODE_TYPE_ELEMENT)
		return LEXBOR_ACTION_OK;

	lxb_tag_id_t tag = lxb_dom_node_tag_id(node);
	if (tag != LXB_TAG_META)
		return LEXBOR_ACTION_OK;

	lxb_char_t* value;
	size_t val_len;

	//<meta data-rh=true property=og:title content=信号与系统漫谈系列之开篇>
	if (is_attr_value(lxb_dom_interface_element(node), "property", "og:title")) {
		value = (lxb_char_t*)lxb_dom_element_get_attribute(
			lxb_dom_interface_element(node), "content", strlen("content"), &val_len);
		if (value) {
			write_head(fp, value, 1);
		}
		return LEXBOR_ACTION_OK;
	}

	//<meta data-rh=true property=og:url content=https://zhuanlan.zhihu.com/p/461247854>
	if (is_attr_value(lxb_dom_interface_element(node), "property", "og:url")) {
		value = (lxb_char_t*)lxb_dom_element_get_attribute(
			lxb_dom_interface_element(node), "content", strlen("content"), &val_len);
		if (value) {
			write_link(fp, "original link", value);
			fprintf(fp, "\n");
			write_latex_hor(fp);
		}
		return LEXBOR_ACTION_OK;
	}

	//cover
	//<meta data-rh="true" property="og:image"
	//content = "https://pica.zhimg.com/v2-751c0ed764f67908bc360993fc305648_720w.jpg?
	if (is_attr_value(lxb_dom_interface_element(node), "property", "og:image")) {
		value = (lxb_char_t*)lxb_dom_element_get_attribute(
			lxb_dom_interface_element(node), "content", strlen("content"), &val_len);
		if(!value)
			return LEXBOR_ACTION_STOP;
		
		char* tail;
		char file_name[256];
		tail = strstr(value, "?source=");
		if (!tail)
			return LEXBOR_ACTION_STOP;
		*tail = 0;
		get_filename(value, file_name);
		if (!file_name[0]) {
			return LEXBOR_ACTION_STOP;
		}

		write_image_path(fp, file_name, NULL);
		exec_curl(output_path, file_name, value);
		
		//skip others
		return LEXBOR_ACTION_STOP;
	}
	
	return LEXBOR_ACTION_OK;
}

void handle_title(FILE* fp, lxb_dom_node_t* node)
{
	lxb_char_t* str;
	size_t str_len;

	lxb_tag_id_t tag = lxb_dom_node_tag_id(node);
	str = lxb_dom_node_text_content(node, &str_len);
	if (!str)
		return;
	if(tag == LXB_TAG_H2)
		write_head(fp, str, 2);
	else
		write_head(fp, str, 3);
}

lexbor_action_t content_walker(lxb_dom_node_t* node, void* ctx)
{
	switch (node->type) {
	case LXB_DOM_NODE_TYPE_ELEMENT:
	case LXB_DOM_NODE_TYPE_TEXT:
		break;
	default: //skip others
		return LEXBOR_ACTION_OK;
	}

	FILE* fp = (FILE*)ctx;
	lxb_char_t* str;
	size_t str_len;

	lxb_tag_id_t tag = lxb_dom_node_tag_id(node);
	switch (tag) {
	case LXB_TAG_CODE:
		str = (char*)lxb_dom_node_text_content(node, &str_len);
		if (str)
			fprintf(fp, "```\n%s\n```\n", str);
		break;
	case LXB_TAG_H2:
	case LXB_TAG_H3:
		handle_title(fp, node);
		break;
	case LXB_TAG_BR:
		fprintf(fp, "\n");
		break;
	case LXB_TAG_OL:
	case LXB_TAG_UL:
		handle_ul(fp, node);
		return LEXBOR_ACTION_NEXT;
	case LXB_TAG_FIGURE:
		//download figure and modify path
		download_image(fp, node);
		break;
	case LXB_TAG_A:
		handle_tagA(fp, node);
		break;
	case LXB_TAG_TABLE:
		handle_table(fp, node);
		break;
	case LXB_TAG_P:
		str = lxb_dom_node_text_content(node, &str_len);
		if (!str)
			break;
		write_content_text(fp, node, str);
		return LEXBOR_ACTION_NEXT;
	case LXB_TAG_HR:
		write_latex_hor(fp);
		break;
	default:
		break;
	}
	
	return LEXBOR_ACTION_OK;
}

void write_markdwon(lxb_html_document_t* doc, FILE* fp)
{
	lxb_dom_node_t* node = lxb_dom_interface_node(doc);

	//1. <meta>
	lxb_dom_node_simple_walk(node, meta_walker, (void*)fp);

	//2. locate the first <p>
	lxb_dom_collection_t* collection;
	collection = get_nodes_by_tag(node, "p");
	size_t len = lxb_dom_collection_length(collection);
	if (!collection || (len == 0)) //no content
		return;

	lxb_dom_element_t* element = lxb_dom_collection_element(collection, 0);
	node = lxb_dom_interface_node(element);
	node = lxb_dom_node_parent(node);
	lxb_dom_collection_destroy(collection, true);

	//3. <span class=ztext-math data-eeimg=1 data-tex=h(t)>
	// find all Latex code and change node
	change_span_latex_nodes(node);
	 
	//4. content and pictures
	lxb_dom_node_simple_walk(node, content_walker, (void*)fp);
}

int main(int argc, char** argv)
{
	if (!DirectoryExists(OUTPUT_PATH)) {
		sprintf(gcmd, "mkdir %s", OUTPUT_PATH);
		system(gcmd);
	}

	//1. read html file to RAM
	size_t count;
	count = sizeof(read_buf);
	FILE* fd = fopen(argv[1], "r");
	if (!fd) {
		printf("can't open %s\n", argv[1]);
		return -1;
	}
	count = fread(read_buf, 1, count, fd);
	fclose(fd);
	read_buf[count] = 0;

	//2. parse html
	lxb_html_document_t* doc;
	doc = parser_init(read_buf, count);
	if (!doc) {
		printf("parser html error\n");
		return -1;
	}

	//3. parse html and write to xxx.md
	FILE* fpMarkDown = creat_markdown_file(argv[1]);
	if (fpMarkDown) {
		//start to write
		write_markdwon(doc, fpMarkDown);
		fclose(fpMarkDown);
	}

	parse_exit(doc);
	return 0;
}

